﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockFinder.DataAccess;
using StockFinder.Model;

namespace StockFinder.Services.PriceDatabaseAnalysers
{
    public class FlatBasePriceDatabaseAnalyser
    {
        public PriceDatabaseAnalyserResult AnalysePrices(List<DailyPrice> prices)
        {
            var result = new PriceDatabaseAnalyserResult();

            if (prices != null && prices.Count > 0)
            {
                //order the prices
                var orderedPrices = prices.OrderByDescending(p => p.PriceDate);

                var weeklyPrices = orderedPrices.AsWeeklyPrices();

                //flat base is at least 5 weeks long
                if (weeklyPrices.Count() >= 5)
                {
                    var orderedWeeklyPrices = weeklyPrices.OrderByDescending(i => i.Year).ThenByDescending(i => i.WeekOfYear);

                    decimal latestWeeklyHigh = orderedWeeklyPrices.ElementAt(0).GetWeeklyHigh();
                    decimal maximumHigh = latestWeeklyHigh;
                    decimal maximumLow = orderedWeeklyPrices.ElementAt(0).GetWeeklyLow();
                    decimal depth = 0;
                    int weekCount = 0;
                    int baseLength = 0;

                    //loop prices
                    foreach (WeeklyPrice weeklyPrice in orderedWeeklyPrices)
                    {
                        var lastPrice = prices.ElementAt(0);

                        result.BaseDepth = depth;
                        result.PreviousHighPrice = maximumHigh;
                        result.BaseLowPrice = maximumLow;
                        result.DaysOfPrices = prices.Count();
                        result.BaseLength = baseLength;
                        result.LastPriceDate = lastPrice.PriceDate;

                        var sma50 = orderedPrices.GetSimpleMovingAverage(50);

                        if (sma50 > 0)
                        {
                            var percentFromSMA50 = lastPrice.AdjustedClose - sma50;

                            percentFromSMA50 = (percentFromSMA50 / sma50) * 100;

                            result.PercentFromSMA50 = percentFromSMA50;
                        }

                        //new week
                        weekCount++;

                        #region Validate week prices

                        //check not empty prices
                        if (weeklyPrice.GetWeeklyOpen() == 0)
                        {
                            break;
                        }

                        #endregion

                        #region Set week high and low

                        //do we have a new peak?
                        if (weeklyPrice.GetWeeklyHigh() > maximumHigh)
                        {
                            //yes
                            maximumHigh = weeklyPrice.GetWeeklyHigh();
                        }

                        //do we have a new low point?
                        if (weeklyPrice.GetWeeklyLow() < maximumLow)
                        {
                            //yes
                            maximumLow = weeklyPrice.GetWeeklyLow();
                        }

                        #endregion

                        #region Calculate the base depth

                        //calculate depth
                        depth = ((maximumHigh - maximumLow) / maximumHigh) * 100;

                        #endregion

                        #region Flat base check

                        //have we breached base depth?
                        if (depth > 15)
                        {
                            //yes so check base length
                            if (baseLength > 5)
                            {
                                //succeeded
                                result.Succeeded = true;
                            }

                            //depth level breached so quit loop
                            break;
                        }
                        else
                        {
                            //no so check if this week was a valid base start
                            if (weeklyPrice.GetWeeklyHigh() == maximumHigh)
                            {
                                //yes so determine new base length
                                baseLength = weekCount;
                            }

                            //go to next week in loop
                        }

                        #endregion
                    }
                }
                else
                {
                    result.Succeeded = false;
                }
            }

            return result;
        }        
    }
}
